/**
 * 用户日志收集器（UserLogger）
 *
 * @fileoverview 收集面向用户的日志，存储在Job表中供UI展示
 * 与文件日志系统分离，提供简洁、用户友好的日志消息
 */

import type { UserLog } from './types'
import { getDatabase } from '../db/index'
import { translateError } from './error-translations'
import { shouldLogUserStep, trimLogs } from './log-sampling'
import { translateStep } from './step-translations'

/**
 * 用户日志收集器
 *
 * 负责收集和存储面向用户的日志信息，这些日志将显示在UI界面上
 */
export class UserLogger {
  /**
   * 记录步骤日志
   *
   * @param jobId - 任务ID
   * @param stepName - 步骤名称（技术名称，会被翻译）
   * @param progress - 进度百分比（0-100）
   * @param message - 自定义消息（可选，如果不提供则使用翻译后的步骤名）
   */
  static async step(
    jobId: string,
    stepName: string,
    progress: number,
    message?: string,
  ): Promise<void> {
    // 检查采样策略
    if (!shouldLogUserStep(stepName)) {
      return
    }

    try {
      // 翻译步骤名称
      const userMessage = message || translateStep(stepName)
      const timestamp = Math.floor(Date.now() / 1000)

      const prisma = getDatabase()

      // 获取现有的日志
      const row = await prisma.job.findUnique({
        where: { id: jobId },
        select: { result: true },
      })

      const result = row?.result ? JSON.parse(row.result as string) : {}
      const logs: UserLog[] = Array.isArray(result.logs) ? result.logs : []

      // 添加新日志
      logs.push({
        timestamp,
        level: 'user-info',
        message: userMessage,
        step: stepName,
        progress: Math.max(0, Math.min(100, progress)),
      })

      // 限制日志数量
      const trimmedLogs = trimLogs(logs)

      // 异步更新Job表（不阻塞主流程）
      // 使用 setImmediate 确保异步执行
      setImmediate(async () => {
        try {
          await prisma.job.update({
            where: { id: jobId },
            data: {
              result: JSON.stringify({ ...result, logs: trimmedLogs }),
              progress: Math.max(0, Math.min(100, progress)),
              current_step: userMessage,
              updated_at: timestamp,
            },
          })
        }
        catch (error) {
          // 日志写入失败不应影响主流程，只记录错误
          console.error('UserLogger.step 写入失败:', error)
        }
      })
    }
    catch (error) {
      // 日志收集失败不应影响主流程
      console.error('UserLogger.step 失败:', error)
    }
  }

  /**
   * 记录警告日志
   *
   * @param jobId - 任务ID
   * @param message - 警告消息
   * @param suggestion - 处理建议（可选）
   */
  static async warn(
    jobId: string,
    message: string,
    suggestion?: string,
  ): Promise<void> {
    try {
      const timestamp = Math.floor(Date.now() / 1000)

      const prisma = getDatabase()

      const row = await prisma.job.findUnique({
        where: { id: jobId },
        select: { result: true },
      })

      const result = row?.result ? JSON.parse(row.result as string) : {}
      const logs: UserLog[] = Array.isArray(result.logs) ? result.logs : []

      logs.push({
        timestamp,
        level: 'user-warn',
        message,
        details: suggestion ? { suggestion } : undefined,
      })

      const trimmedLogs = trimLogs(logs)

      setImmediate(async () => {
        try {
          await prisma.job.update({
            where: { id: jobId },
            data: {
              result: JSON.stringify({ ...result, logs: trimmedLogs }),
              updated_at: timestamp,
            },
          })
        }
        catch (error) {
          console.error('UserLogger.warn 写入失败:', error)
        }
      })
    }
    catch (error) {
      console.error('UserLogger.warn 失败:', error)
    }
  }

  /**
   * 记录错误日志
   *
   * @param jobId - 任务ID
   * @param error - 错误对象或错误消息
   * @param context - 错误发生的上下文（可选）
   */
  static async error(
    jobId: string,
    error: Error | string,
    context?: string,
  ): Promise<void> {
    try {
      // 翻译错误信息
      const translation = translateError(error, context)

      const timestamp = Math.floor(Date.now() / 1000)

      const prisma = getDatabase()

      const row = await prisma.job.findUnique({
        where: { id: jobId },
        select: { result: true },
      })

      const result = row?.result ? JSON.parse(row.result as string) : {}
      const logs: UserLog[] = Array.isArray(result.logs) ? result.logs : []

      const errorMessage = typeof error === 'string' ? error : error.message

      logs.push({
        timestamp,
        level: 'user-error',
        message: translation.message,
        details: {
          error: errorMessage,
          suggestion: translation.suggestion,
        },
      })

      const trimmedLogs = trimLogs(logs)

      setImmediate(async () => {
        try {
          await prisma.job.update({
            where: { id: jobId },
            data: {
              result: JSON.stringify({ ...result, logs: trimmedLogs }),
              updated_at: timestamp,
            },
          })
        }
        catch (error) {
          console.error('UserLogger.error 写入失败:', error)
        }
      })
    }
    catch (error) {
      console.error('UserLogger.error 失败:', error)
    }
  }
}
